﻿using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.AspNetCore.DataProtection.KeyManagement;

namespace api_test_net_8.Controllers
{
    public class LoginModel
    {
        /// <summary>
        /// Username
        /// </summary>
        public required string Username { get; set; }
        /// <summary>
        /// Password
        /// </summary>
        public required string Password { get; set; }
    }

    [ApiController]
    [Route("api/[controller]")]
    public class AccountController : ControllerBase
    {
        /// <summary>
        /// 
        /// </summary>
        private readonly IConfiguration _configuration;
        /// <summary>
        /// 
        /// </summary>
        private readonly int _expirationHours;

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="configuration"></param>
        public AccountController(IConfiguration configuration)
        {
            _configuration = configuration;
            _expirationHours = Convert.ToInt32(_configuration["Jwt:ExpirationHours"]);
            if (_expirationHours < 12)
            {
                _expirationHours = 12;
            }
        }


        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("login")]
        public async Task<object> Login([FromBody] LoginModel model)
        {
            if (model.Username != "guest" || model.Password != "123456")
            {
                return Unauthorized();
            }
            return await loginAsync(model);
        }

        /// <summary>
        /// 登录接口
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("login/admin")]
        public async Task<object> LoginAdmin([FromBody] LoginModel model)
        {
            if (model.Username != "admin" || model.Password != "123456")
            {
                return Unauthorized();
            }
            return await loginAsync(model);
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        private async Task<object> loginAsync(LoginModel model)
        {
            await Task.Delay(0);
            var token = generateJwtToken(model.Username, out List<Claim> claims);

            Console.WriteLine($"生产Token: {token}");
            bool jwtUsingCookie = Convert.ToBoolean(_configuration["JwtCookie:Enabled"]);
            SameSiteMode sameSiteMode = (SameSiteMode)Enum.Parse(typeof(SameSiteMode), _configuration["JwtCookie:SameSiteMode"]);
            //sameSiteMode = SameSiteMode.Strict;
            //jwtUsingCookie = false;
            if (jwtUsingCookie)
            {
                var cookieOptions = new CookieOptions
                {
                    HttpOnly = true,
                    //Secure = true, // 在生产环境中应使用 HTTPS
                    //Secure = !GloabConfig.IsDevelopment, // 开发环境允许 HTTP
                    SameSite = sameSiteMode,
                    Expires = DateTime.Now.AddHours(_expirationHours),
                    IsEssential = true
                };
                Response.Cookies.Append("jwt_token", token, cookieOptions);

                return new
                {
                    Code = 200,
                    Message = "登录成功"
                };
            }
            else
            {
                return new
                {
                    Code = 200,
                    Data = token,
                    Message = "登录成功"
                };
            }
        }


        /// <summary>
        /// 登出接口
        /// </summary>
        /// <returns></returns>
        [HttpPost("logout")]
        public object Logout()
        {
            Response.Cookies.Delete("jwt_token");
            return new
            {
                Code = 200,
                Message = "登出成功"
            };
        }

        [HttpGet("debug-user")]
        public IActionResult DebugUser()
        {
            var user = User;
            var isAuthenticated = user.Identity?.IsAuthenticated;
            var claims = user.Claims.Select(c => new { c.Type, c.Value });

            Console.WriteLine($"isAuthenticated:{isAuthenticated},{claims}");

            return Ok(new
            {
                IsAuthenticated = isAuthenticated,
                Claims = claims
            });
        }

        /// <summary>
        /// 受保护的资源
        /// </summary>
        /// <returns></returns>
        [HttpGet("resource/everyone")]
        public object EveryoneResource()
        {
            return new
            {
                Code = 200,
                Message = "这是所有人可见的资源",
                User = User.Identity?.Name
            };
        }

        /// <summary>
        /// 受保护的资源
        /// </summary>
        /// <returns></returns>
        [HttpGet("resource/guest")]
        [Authorize]
        public object GuestResource()
        {
            DebugUser();
            return new { 
                Code = 200,
                Message = "这是受保护的资源", 
                User = User.Identity?.Name 
            };
        }

        /// <summary>
        /// 管理员专用资源
        /// </summary>
        /// <returns></returns>
        [HttpGet("resource/admin")]
        [Authorize(Policy = "AdminOnly")]
        public object AdminResource()
        {
            return new
            {
                Code = 200,
                Message = "这是管理员专用资源",
                User = User.Identity?.Name
            };
        }

        /// <summary>
        /// 生成 JWT Token 的辅助方法
        /// </summary>
        /// <param name="username"></param>
        /// <param name="claims"></param>
        /// <returns></returns>
        private string generateJwtToken(string username, out List<Claim> claims)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
            claims = new List<Claim>();
            claims.Add(new Claim(ClaimTypes.Name, username));
            claims.Add(new Claim(ClaimTypes.Role, username == "admin" ? "Admin" : "Guest"));

            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.Now.AddHours(_expirationHours),
                Issuer = _configuration["Jwt:Issuer"],
                Audience = _configuration["Jwt:Audience"],
                SigningCredentials = new SigningCredentials(
                    new SymmetricSecurityKey(key),
                    SecurityAlgorithms.HmacSha256Signature)
            };

            var tokenDescriptor2 = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {
                    new Claim(ClaimTypes.Name, username),
                    new Claim(ClaimTypes.Role, "Admin") // 示例角色
                }),
                Expires = DateTime.UtcNow.AddHours(1),
                Issuer = _configuration["Jwt:Issuer"],
                Audience = _configuration["Jwt:Audience"],
                SigningCredentials = new SigningCredentials(
                    new SymmetricSecurityKey(key),
                    SecurityAlgorithms.HmacSha256Signature)
            };

            var token = tokenHandler.CreateToken(tokenDescriptor);
            return tokenHandler.WriteToken(token);
        }


        /// <summary>
        /// 受保护的资源
        /// </summary>
        /// <returns></returns>
        [HttpGet("cookie")]
        public async Task<object> GetCookie()
        {
            return await setCookie();
        }

        /// <summary>
        /// 受保护的资源
        /// </summary>
        /// <returns></returns>
        [HttpPost("cookie")]
        public async Task<object> PostCookie()
        {
            return await setCookie();
        }

        private async Task<object> setCookie()
        {
            await Task.Delay(0);
            const string key = "account_test_cookie";
            var value = DateTime.Now.ToString("yyyy-MM-dd HH:ss:ss");
            Response.Cookies.Append(key, value, new CookieOptions { HttpOnly = true });

            return new
            {
                Code = 200,
                Message = $"{key}={value}"
            };
        }


    }

}
